use flate2::write::GzEncoder;
use git2;
use rustc_serialize::hex::ToHex;
-use tar::Archive;
+use tar::{Archive, Header};
use url::Url;
-use support::project;
use support::paths;
use support::git::repo;
use cargo::util::Sha256;
pub fn dl_path() -> PathBuf { paths::root().join("dl") }
pub fn dl_url() -> Url { Url::from_file_path(&*dl_path()).ok().unwrap() }
-pub fn init() {
+pub struct Package {
+ name: String,
+ vers: String,
+ deps: Vec<(String, String, &'static str)>,
+ files: Vec<(String, String)>,
+ yanked: bool,
+}
+
+fn init() {
let config = paths::home().join(".cargo/config");
fs::create_dir_all(config.parent().unwrap()).unwrap();
+ if fs::metadata(&config).is_ok() {
+ return
+ }
File::create(&config).unwrap().write_all(format!(r#"
[registry]
index = "{reg}"
.build();
}
-pub fn mock_archive(name: &str, version: &str, deps: &[(&str, &str, &str)]) {
- let mut manifest = format!(r#"
- [package]
- name = "{}"
- version = "{}"
- authors = []
- "#, name, version);
- for &(dep, req, kind) in deps.iter() {
- manifest.push_str(&format!(r#"
- [{}dependencies.{}]
- version = "{}"
- "#, match kind {
- "build" => "build-",
- "dev" => "dev-",
- _ => ""
- }, dep, req));
+impl Package {
+ pub fn new(name: &str, vers: &str) -> Package {
+ init();
+ Package {
+ name: name.to_string(),
+ vers: vers.to_string(),
+ deps: Vec::new(),
+ files: Vec::new(),
+ yanked: false,
+ }
}
- let p = project(name)
- .file("Cargo.toml", &manifest)
- .file("src/lib.rs", "")
- .file("src/main.rs", &format!("\
- extern crate {};
- fn main() {{}}
- ", name));
- p.build();
-
- let dst = mock_archive_dst(name, version);
- fs::create_dir_all(dst.parent().unwrap()).unwrap();
- let f = File::create(&dst).unwrap();
- let a = Archive::new(GzEncoder::new(f, Default));
- a.append_file(&format!("{}-{}/Cargo.toml", name, version),
- &mut File::open(&p.root().join("Cargo.toml")).unwrap()).unwrap();
- a.append_file(&format!("{}-{}/src/lib.rs", name, version),
- &mut File::open(&p.root().join("src/lib.rs")).unwrap()).unwrap();
- a.append_file(&format!("{}-{}/src/main.rs", name, version),
- &mut File::open(&p.root().join("src/main.rs")).unwrap()).unwrap();
- a.finish().unwrap();
-}
-pub fn mock_archive_dst(name: &str, version: &str) -> PathBuf {
- dl_path().join(name).join(version).join("download")
-}
+ pub fn file(&mut self, name: &str, contents: &str) -> &mut Package {
+ self.files.push((name.to_string(), contents.to_string()));
+ self
+ }
-pub fn mock_pkg(name: &str, version: &str, deps: &[(&str, &str, &str)]) {
- mock_pkg_yank(name, version, deps, false)
-}
+ pub fn dep(&mut self, name: &str, vers: &str) -> &mut Package {
+ self.deps.push((name.to_string(), vers.to_string(), "normal"));
+ self
+ }
-pub fn mock_pkg_yank(name: &str, version: &str, deps: &[(&str, &str, &str)],
- yanked: bool) {
- mock_archive(name, version, deps);
- let mut c = Vec::new();
- File::open(&mock_archive_dst(name, version)).unwrap()
- .read_to_end(&mut c).unwrap();
- let line = pkg(name, version, deps, &cksum(&c), yanked);
-
- let file = match name.len() {
- 1 => format!("1/{}", name),
- 2 => format!("2/{}", name),
- 3 => format!("3/{}/{}", &name[..1], name),
- _ => format!("{}/{}/{}", &name[0..2], &name[2..4], name),
- };
- publish(&file, &line);
-}
+ pub fn dev_dep(&mut self, name: &str, vers: &str) -> &mut Package {
+ self.deps.push((name.to_string(), vers.to_string(), "dev"));
+ self
+ }
+
+ pub fn yanked(&mut self, yanked: bool) -> &mut Package {
+ self.yanked = yanked;
+ self
+ }
+
+ #[allow(deprecated)] // connect => join in 1.3
+ pub fn publish(&self) {
+ self.make_archive();
-pub fn publish(file: &str, line: &str) {
- let repo = git2::Repository::open(®istry_path()).unwrap();
- let mut index = repo.index().unwrap();
- {
- let dst = registry_path().join(file);
+ // Figure out what we're going to write into the index
+ let deps = self.deps.iter().map(|&(ref name, ref req, ref kind)| {
+ format!("{{\"name\":\"{}\",\
+ \"req\":\"{}\",\
+ \"features\":[],\
+ \"default_features\":false,\
+ \"target\":null,\
+ \"optional\":false,\
+ \"kind\":\"{}\"}}", name, req, kind)
+ }).collect::<Vec<_>>().connect(",");
+ let cksum = {
+ let mut c = Vec::new();
+ File::open(&self.archive_dst()).unwrap()
+ .read_to_end(&mut c).unwrap();
+ cksum(&c)
+ };
+ let line = format!("{{\"name\":\"{}\",\"vers\":\"{}\",\
+ \"deps\":[{}],\"cksum\":\"{}\",\"features\":{{}},\
+ \"yanked\":{}}}",
+ self.name, self.vers, deps, cksum, self.yanked);
+ let file = match self.name.len() {
+ 1 => format!("1/{}", self.name),
+ 2 => format!("2/{}", self.name),
+ 3 => format!("3/{}/{}", &self.name[..1], self.name),
+ _ => format!("{}/{}/{}", &self.name[0..2], &self.name[2..4], self.name),
+ };
+
+ // Write file/line in the index
+ let dst = registry_path().join(&file);
let mut prev = String::new();
let _ = File::open(&dst).and_then(|mut f| f.read_to_string(&mut prev));
fs::create_dir_all(dst.parent().unwrap()).unwrap();
File::create(&dst).unwrap()
- .write_all((prev + line + "\n").as_bytes()).unwrap();
+ .write_all((prev + &line[..] + "\n").as_bytes()).unwrap();
+
+ // Add the new file to the index
+ let repo = git2::Repository::open(®istry_path()).unwrap();
+ let mut index = repo.index().unwrap();
+ index.add_path(Path::new(&file)).unwrap();
+ index.write().unwrap();
+ let id = index.write_tree().unwrap();
+
+ // Commit this change
+ let tree = repo.find_tree(id).unwrap();
+ let sig = repo.signature().unwrap();
+ let parent = repo.refname_to_id("refs/heads/master").unwrap();
+ let parent = repo.find_commit(parent).unwrap();
+ repo.commit(Some("HEAD"), &sig, &sig,
+ "Another commit", &tree,
+ &[&parent]).unwrap();
}
- index.add_path(Path::new(file)).unwrap();
- index.write().unwrap();
- let id = index.write_tree().unwrap();
- let tree = repo.find_tree(id).unwrap();
- let sig = repo.signature().unwrap();
- let parent = repo.refname_to_id("refs/heads/master").unwrap();
- let parent = repo.find_commit(parent).unwrap();
- repo.commit(Some("HEAD"), &sig, &sig,
- "Another commit", &tree,
- &[&parent]).unwrap();
-}
-#[allow(deprecated)] // connect => join in 1.3
-pub fn pkg(name: &str, vers: &str, deps: &[(&str, &str, &str)], cksum: &str,
- yanked: bool) -> String {
- let deps = deps.iter().map(|&(a, b, c)| dep(a, b, c)).collect::<Vec<String>>();
- format!("{{\"name\":\"{}\",\"vers\":\"{}\",\
- \"deps\":[{}],\"cksum\":\"{}\",\"features\":{{}},\
- \"yanked\":{}}}",
- name, vers, deps.connect(","), cksum, yanked)
-}
+ fn make_archive(&self) {
+ let mut manifest = format!(r#"
+ [package]
+ name = "{}"
+ version = "{}"
+ authors = []
+ "#, self.name, self.vers);
+ for &(ref dep, ref req, kind) in self.deps.iter() {
+ manifest.push_str(&format!(r#"
+ [{}dependencies.{}]
+ version = "{}"
+ "#, match kind {
+ "build" => "build-",
+ "dev" => "dev-",
+ _ => ""
+ }, dep, req));
+ }
-pub fn dep(name: &str, req: &str, kind: &str) -> String {
- format!("{{\"name\":\"{}\",\
- \"req\":\"{}\",\
- \"features\":[],\
- \"default_features\":false,\
- \"target\":null,\
- \"optional\":false,\
- \"kind\":\"{}\"}}", name, req, kind)
+ let dst = self.archive_dst();
+ fs::create_dir_all(dst.parent().unwrap()).unwrap();
+ let f = File::create(&dst).unwrap();
+ let a = Archive::new(GzEncoder::new(f, Default));
+ self.append(&a, "Cargo.toml", &manifest);
+ if self.files.len() == 0 {
+ self.append(&a, "src/lib.rs", "");
+ } else {
+ for &(ref name, ref contents) in self.files.iter() {
+ self.append(&a, name, contents);
+ }
+ }
+ a.finish().unwrap();
+ }
+
+ fn append<W: Write>(&self, ar: &Archive<W>, file: &str, contents: &str) {
+ let mut header = Header::new();
+ header.set_size(contents.len() as u64);
+ header.set_path(format!("{}-{}/{}", self.name, self.vers, file)).unwrap();
+ header.set_cksum();
+
+ ar.append(&header, &mut contents.as_bytes()).unwrap();
+ }
+
+ pub fn archive_dst(&self) -> PathBuf {
+ dl_path().join(&self.name).join(&self.vers).join("download")
+ }
}
-pub fn cksum(s: &[u8]) -> String {
+fn cksum(s: &[u8]) -> String {
let mut sha = Sha256::new();
sha.update(s);
sha.finish().to_hex()
use support::{project, execs, cargo_dir};
use support::{UPDATING, DOWNLOADING, COMPILING, PACKAGING, VERIFYING, ADDING, REMOVING};
use support::paths::{self, CargoPathExt};
-use support::registry as r;
+use support::registry::{self, Package};
use support::git;
use hamcrest::assert_that;
fn setup() {
- r::init();
}
test!(simple {
"#)
.file("src/main.rs", "fn main() {}");
- r::mock_pkg("bar", "0.0.1", &[]);
+ Package::new("bar", "0.0.1").publish();
assert_that(p.cargo_process("build"),
execs().with_status(0).with_stdout(&format!("\
downloading = DOWNLOADING,
compiling = COMPILING,
dir = p.url(),
- reg = r::registry())));
+ reg = registry::registry())));
// Don't download a second time
assert_that(p.cargo_process("build"),
",
updating = UPDATING,
dir = p.url(),
- reg = r::registry())));
+ reg = registry::registry())));
});
test!(deps {
"#)
.file("src/main.rs", "fn main() {}");
- r::mock_pkg("baz", "0.0.1", &[]);
- r::mock_pkg("bar", "0.0.1", &[("baz", "*", "normal")]);
+ Package::new("baz", "0.0.1").publish();
+ Package::new("bar", "0.0.1").dep("baz", "*").publish();
assert_that(p.cargo_process("build"),
execs().with_status(0).with_stdout(&format!("\
downloading = DOWNLOADING,
compiling = COMPILING,
dir = p.url(),
- reg = r::registry())));
+ reg = registry::registry())));
});
test!(nonexistent {
+ Package::new("init", "0.0.1").publish();
+
let p = project("foo")
.file("Cargo.toml", r#"
[project]
"#)
.file("src/main.rs", "fn main() {}");
- r::mock_pkg("foo", "0.0.1", &[]);
- r::mock_pkg("foo", "0.0.2", &[]);
+ Package::new("foo", "0.0.1").publish();
+ Package::new("foo", "0.0.2").publish();
assert_that(p.cargo_process("build"),
execs().with_status(101).with_stderr("\
versions found: 0.0.2, 0.0.1
"));
- r::mock_pkg("foo", "0.0.3", &[]);
- r::mock_pkg("foo", "0.0.4", &[]);
+ Package::new("foo", "0.0.3").publish();
+ Package::new("foo", "0.0.4").publish();
assert_that(p.cargo_process("build"),
execs().with_status(101).with_stderr("\
"#)
.file("src/main.rs", "fn main() {}");
- r::mock_pkg("bad-cksum", "0.0.1", &[]);
- File::create(&r::mock_archive_dst("bad-cksum", "0.0.1")).unwrap();
+ let pkg = Package::new("bad-cksum", "0.0.1");
+ pkg.publish();
+ File::create(&pkg.archive_dst()).unwrap();
assert_that(p.cargo_process("build").arg("-v"),
execs().with_status(101).with_stderr("\
});
test!(update_registry {
+ Package::new("init", "0.0.1").publish();
+
let p = project("foo")
.file("Cargo.toml", r#"
[project]
version required: >= 0.0.0
"));
- r::mock_pkg("notyet", "0.0.1", &[]);
+ Package::new("notyet", "0.0.1").publish();
assert_that(p.cargo("build"),
execs().with_status(0).with_stdout(&format!("\
downloading = DOWNLOADING,
compiling = COMPILING,
dir = p.url(),
- reg = r::registry())));
+ reg = registry::registry())));
});
test!(package_with_path_deps {
+ Package::new("init", "0.0.1").publish();
+
let p = project("foo")
.file("Cargo.toml", r#"
[project]
version required: ^0.0.1
"));
- r::mock_pkg("notyet", "0.0.1", &[]);
+ Package::new("notyet", "0.0.1").publish();
assert_that(p.cargo("package"),
execs().with_status(0).with_stdout(format!("\
.file("src/main.rs", "fn main() {}");
p.build();
- r::mock_pkg("bar", "0.0.1", &[]);
+ Package::new("bar", "0.0.1").publish();
assert_that(p.cargo("build"),
execs().with_status(0).with_stdout(&format!("\
dir = p.url())));
p.root().move_into_the_past().unwrap();
- r::mock_pkg("bar", "0.0.2", &[]);
+ Package::new("bar", "0.0.2").publish();
assert_that(p.cargo("build"),
execs().with_status(0).with_stdout(""));
.file("src/main.rs", "fn main() {}");
p.build();
- r::mock_pkg("baz", "0.0.1", &[]);
- r::mock_pkg("bar", "0.0.1", &[("baz", "*", "normal")]);
+ Package::new("baz", "0.0.1").publish();
+ Package::new("bar", "0.0.1").dep("baz", "*").publish();
assert_that(p.cargo("build"),
execs().with_status(0).with_stdout(&format!("\
dir = p.url())));
p.root().move_into_the_past().unwrap();
- r::mock_pkg("baz", "0.0.2", &[]);
- r::mock_pkg("bar", "0.0.2", &[("baz", "*", "normal")]);
+ Package::new("baz", "0.0.2").publish();
+ Package::new("bar", "0.0.2").dep("baz", "*").publish();
assert_that(p.cargo("build"),
execs().with_status(0).with_stdout(""));
.file("src/main.rs", "fn main() {}");
p.build();
- r::mock_pkg("baz", "0.0.1", &[]);
- r::mock_pkg_yank("baz", "0.0.2", &[], true);
- r::mock_pkg("bar", "0.0.1", &[("baz", "*", "normal")]);
- r::mock_pkg_yank("bar", "0.0.2", &[("baz", "*", "normal")], true);
+ Package::new("baz", "0.0.1").publish();
+ Package::new("baz", "0.0.2").yanked(true).publish();
+ Package::new("bar", "0.0.1").dep("baz", "*").publish();
+ Package::new("bar", "0.0.2").dep("baz", "*").yanked(true).publish();
assert_that(p.cargo("build"),
execs().with_status(0).with_stdout(&format!("\
.file("src/main.rs", "fn main() {}");
p.build();
- r::mock_pkg("baz", "0.0.1", &[]);
- r::mock_pkg_yank("baz", "0.0.2", &[], true);
- r::mock_pkg("bar", "0.0.1", &[("baz", "=0.0.2", "normal")]);
+ Package::new("baz", "0.0.1").publish();
+ Package::new("baz", "0.0.2").yanked(true).publish();
+ Package::new("bar", "0.0.1").dep("baz", "=0.0.2").publish();
assert_that(p.cargo("build"),
execs().with_status(101).with_stderr("\
.file("src/main.rs", "fn main() {}");
p.build();
- r::mock_pkg("bar", "0.0.1", &[]);
+ Package::new("bar", "0.0.1").publish();
assert_that(p.cargo("build"),
execs().with_status(0));
- fs::remove_dir_all(&r::registry_path().join("3")).unwrap();
+ fs::remove_dir_all(®istry::registry_path().join("3")).unwrap();
- r::mock_pkg_yank("bar", "0.0.1", &[], true);
+ Package::new("bar", "0.0.1").yanked(true).publish();
assert_that(p.cargo("build"),
execs().with_status(0).with_stdout(""));
.file("src/main.rs", "fn main() {}");
p.build();
- r::mock_pkg("bar", "0.0.1", &[]);
+ Package::new("bar", "0.0.1").publish();
assert_that(p.cargo("build"),
execs().with_status(0));
p.root().move_into_the_past().unwrap();
p.build();
println!("0.0.1");
- r::mock_pkg("bar", "0.0.1", &[]);
+ Package::new("bar", "0.0.1").publish();
assert_that(p.cargo("build"),
execs().with_status(0));
- r::mock_pkg("bar", "0.0.2", &[]);
- r::mock_pkg("bar", "0.0.3", &[]);
+ Package::new("bar", "0.0.2").publish();
+ Package::new("bar", "0.0.3").publish();
paths::home().join(".cargo/registry").rm_rf().unwrap();
println!("0.0.2 update");
assert_that(p.cargo("update")
dir = p.url())));
println!("new dependencies update");
- r::mock_pkg("bar", "0.0.4", &[("spam", "0.2.5", "")]);
- r::mock_pkg("spam", "0.2.5", &[]);
+ Package::new("bar", "0.0.4").dep("spam", "0.2.5").publish();
+ Package::new("spam", "0.2.5").publish();
assert_that(p.cargo("update")
.arg("-p").arg("bar"),
execs().with_status(0).with_stdout(&format!("\
", updating = UPDATING, adding = ADDING)));
println!("new dependencies update");
- r::mock_pkg("bar", "0.0.5", &[]);
+ Package::new("bar", "0.0.5").publish();
assert_that(p.cargo("update")
.arg("-p").arg("bar"),
execs().with_status(0).with_stdout(&format!("\
.file("src/main.rs", "fn main() {}");
p.build();
- r::mock_pkg("baz", "0.0.1", &[]);
- r::mock_pkg("bar", "0.0.1", &[("baz", "*", "dev")]);
+ Package::new("baz", "0.0.1").publish();
+ Package::new("bar", "0.0.1").dev_dep("baz", "*").publish();
assert_that(p.cargo("build"),
execs().with_status(0).with_stdout(&format!("\
.file("a/src/lib.rs", "");
p.build();
- r::mock_pkg("bar", "0.0.1", &[]);
+ Package::new("bar", "0.0.1").publish();
assert_that(p.cargo("build"),
execs().with_status(0).with_stdout(&format!("\
[dependencies]
bar = "0.1.0"
"#).unwrap();
- r::mock_pkg("bar", "0.1.0", &[]);
+ Package::new("bar", "0.1.0").publish();
println!("second");
assert_that(p.cargo("build"),
.file("src/main.rs", "fn main() {}");
p.build();
- r::mock_pkg("a", "0.0.1", &[]);
+ Package::new("a", "0.0.1").publish();
p.root().move_into_the_past().unwrap();
assert_that(p.cargo("build"),
.file("src/main.rs", "fn main() {}");
p.build();
- r::mock_pkg("a", "0.1.0", &[]);
+ Package::new("a", "0.1.0").publish();
assert_that(p.cargo("build"),
execs().with_status(0));
-
- r::mock_pkg("a", "0.1.1", &[]);
+ Package::new("a", "0.1.1").publish();
let lock = p.root().join("Cargo.lock");
let mut s = String::new();
.file("src/main.rs", "fn main() {}");
p.build();
- r::mock_pkg("a", "0.1.0", &[]);
+ Package::new("a", "0.1.0").publish();
assert_that(p.cargo("fetch"),
execs().with_status(0)
.file("src/main.rs", "fn main() {}");
p.build();
- r::mock_pkg("a", "0.1.0", &[("b", "*", "normal")]);
- r::mock_pkg("b", "0.1.0", &[]);
+ Package::new("a", "0.1.0").dep("b", "*").publish();
+ Package::new("b", "0.1.0").publish();
assert_that(p.cargo("fetch"),
execs().with_status(0));
- r::mock_pkg("b", "0.1.1", &[]);
+ Package::new("b", "0.1.1").publish();
assert_that(p.cargo("update").arg("-pb"),
execs().with_status(0)
.file("src/main.rs", "fn main() {}");
p.build();
- r::mock_pkg("webdriver", "0.1.0", &[("hyper", "0.6", "normal")]);
- r::mock_pkg("hyper", "0.6.5", &[("openssl", "0.1", "normal"),
- ("cookie", "0.1", "normal")]);
- r::mock_pkg("cookie", "0.1.0", &[("openssl", "0.1", "normal")]);
- r::mock_pkg("openssl", "0.1.0", &[]);
+ Package::new("webdriver", "0.1.0").dep("hyper", "0.6").publish();
+ Package::new("hyper", "0.6.5").dep("openssl", "0.1")
+ .dep("cookie", "0.1")
+ .publish();
+ Package::new("cookie", "0.1.0").dep("openssl", "0.1").publish();
+ Package::new("openssl", "0.1.0").publish();
assert_that(p.cargo("generate-lockfile"),
execs().with_status(0));
- r::mock_pkg("openssl", "0.1.1", &[]);
- r::mock_pkg("hyper", "0.6.6", &[("openssl", "0.1.1", "normal"),
- ("cookie", "0.1.0", "normal")]);
+ Package::new("openssl", "0.1.1").publish();
+ Package::new("hyper", "0.6.6").dep("openssl", "0.1.1")
+ .dep("cookie", "0.1.0")
+ .publish();
assert_that(p.cargo("update").arg("-p").arg("hyper"),
execs().with_status(0)
.file("src/main.rs", "fn main() {}");
p.build();
- r::mock_pkg("a", "0.1.0", &[]);
- r::mock_pkg("b", "0.1.0", &[]);
- r::mock_pkg("c", "0.1.0", &[]);
+ Package::new("a", "0.1.0").publish();
+ Package::new("b", "0.1.0").publish();
+ Package::new("c", "0.1.0").publish();
assert_that(p.cargo("fetch"),
execs().with_status(0));
- r::mock_pkg("a", "0.1.1", &[]);
- r::mock_pkg("b", "0.1.1", &[]);
- r::mock_pkg("c", "0.1.1", &[]);
+ Package::new("a", "0.1.1").publish();
+ Package::new("b", "0.1.1").publish();
+ Package::new("c", "0.1.1").publish();
assert_that(p.cargo("update").arg("-pa").arg("-pb"),
execs().with_status(0)